<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta
            name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
    >
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>监听元素出现在视口中</title>
    <style>
        html, body {
            margin: 0;
            padding: 0;
        }
        body {
            display: grid;
            place-content: center;
            height: 100vh;
        }
        .main {
            display: flex;
        }
        .contents {
            width: 100px;
        }
        .active-tab {
            font-weight: 700;
        }
        .container {
            position: relative;
            width: 300px;
            height: 500px;
            background: azure;
            overflow: auto;
        }
        .list-item {
            width: 90%;
            margin-bottom: 20px;
        }
    </style>
    
</head>
<body>
<section class="main">
    <aside class="contents"></aside>
    <main class="container"></main>
</section>
<script>
    const CONTAINER_HEIGHT = 500;
    const contentList = document.querySelector(".contents");
    const container = document.querySelector(".container");
    let currentTab;
    let viewPortElementEntries = new Map();
    const observeCfg = {
        root: document.querySelector(".container"),
        threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
    };
    const ob = new IntersectionObserver((entries, observer) => {
        for (const entry of entries) {
            if (entry.isIntersecting) {
                viewPortElementEntries.set(entry.target.id, entry);
            } else {
                viewPortElementEntries.delete(entry.target.id);
            }
        }
        console.log("视口内元素：", viewPortElementEntries);
        setActiveTab();
    }, observeCfg);
    function setActiveTab() {
        if (currentTab) {
            document.querySelector(".active-tab").classList.remove("active-tab");
        }
        let order = Infinity;
        for (const [_, v] of viewPortElementEntries) {
            if (v.target.dataset.order < order){
                order = v.target.dataset.order;
                currentTab = v.target.id;
            }
        }
        document.querySelector(`#contents-${currentTab}`).classList.add("active-tab")
        console.log("当前激活tab页签：", currentTab);
    }
    function randomItems(count) {
        const listFrag = document.createDocumentFragment();
        const contentsFrag = document.createDocumentFragment();
        for (let i = 0; i < count; i++) {
            const item = document.createElement("div");
            item.classList.add("list-item");
            item.style.height = `${Math.floor(CONTAINER_HEIGHT * 1.2 * Math.random() + 50)}px`;
            item.style.background = randomColor();
            item.textContent = `TAB${i+1}`;
            item.id = `TAB${i+1}`;
            item.dataset.order = i;
            listFrag.appendChild(item);
            ob.observe(item);
            
            const contentsItem = document.createElement("div");
            contentsItem.textContent = item.id;
            contentsItem.classList.add("contents-item");
            contentsItem.id = `contents-${item.id}`;
            contentsFrag.appendChild(contentsItem);
        }
        container.appendChild(listFrag);
        contentList.appendChild(contentsFrag);
    }
    function randomColor() {
        return `#${Math.random().toString(16).substring(2, 8).padStart(6, '0')}`;
    }
    randomItems(10);
</script>
</body>
</html>